import React, { useEffect, useMemo, useRef } from "react";
import { useRefCallback, udp, Skeleton, type IObject } from "@cscec/udp-ui";
import {
  setMasterOptions,
  getMasterOptions,
} from "@@/plugin-qiankun-master/masterOptions";
import { MicroApp } from "umi";

const defaultProps = {
  autoSetLoading: true,
  settings: {
    singular: false,
    sandbox: { experimentalStyleIsolation: true },
  },
  wrapperClassName: "udp-micro-app",
  className: "udp-micro-app",
  loader: (loading: any) => (
    <Skeleton loading={loading} active style={{ padding: 24 }} />
  ),
  autoCaptureError: true,
  errorBoundary: (error: {
    message:
      | string
      | number
      | boolean
      | React.ReactElement<any, string | React.JSXElementConstructor<any>>
      | React.ReactFragment
      | React.ReactPortal
      | null
      | undefined;
  }) => <div>Error: {error.message}</div>,
};

export function MicroCmp(componentProps: {
  pathname: string;
  name: string;
  entry: string;
  [x: string]: any;
}) {
  const { pathname: url, entry, apiEntry = false, ...rest } = componentProps;
  const appName = componentProps.name;

  useMemo(() => {
    const { apps = [] } = getMasterOptions() as any;
    if (apps.find((app: any) => app.name === appName)) {
      return;
    }
    setMasterOptions({
      apps: [
        ...apps,
        {
          name: appName,
          credentials: false,
          entry,
          props: {
            subRoot: "/",
            appName,
            basePath: `/${appName}`,
            publicPath: ((url) => {
              if (url.indexOf("//") === 0) {
                url = window.location.protocol + url;
              }
              if (url[url.length - 1] === "/") {
                return url;
              }
              return (
                url.match(/^http[s]?:\/\/(.)+\//)?.[0] ||
                `${url.replace("/index.html", "")}/`
              );
            })(entry),
            createPath(microAppPath: string, query?: IObject) {
              return udp.handleUrl(
                `#/${appName}${
                  microAppPath.startsWith("/") ? "" : "/"
                }${microAppPath}`,
                {
                  ...udp.getQueryValue(""),
                  ...query,
                }
              );
            },
            getMasterInfo() {
              const getRoot = () => {
                if (apiEntry) {
                  let _root = udp.isString(apiEntry)
                    ? apiEntry
                    : entry[entry.length - 1] === "/"
                    ? entry
                    : `${entry}/`;
                  if (entry.indexOf("//") === 0) {
                    _root = window.location.protocol + _root;
                  }
                  return _root.match(/^http[s]?:\/\/([^\/])+\//)?.[0] || "/";
                }
                return udp.getRoot();
              };
              return {
                getUser() {
                  return { ...udp.getUser(), root: getRoot() };
                },
                getObserver() {
                  return udp.getPageObserver();
                },
              };
            },
          },
        },
      ],
    });
  }, [appName, entry]);

  const history = useRef<any>();
  // url 的变更不会透传给下游，组件内自己会处理掉，所以这里直接用 ref 来存
  const historyOpts = useRef({
    type: "memory",
    initialEntries: [url],
    initialIndex: 1,
  });

  const historyInitHandler = useRefCallback((h) => {
    // 重写push很关键，让push通过父应用来统一控制
    h.push = (path: any, query: any) => {
      udp.open(path, { microAppName: componentProps.name, ...query });
    };
    history.current = h;
  });

  useEffect(() => {
    // push history for slave app when url property changed
    // the initial url will be ignored because the history has not been initialized
    if (history.current && url) {
      history.current.push(url);
    }
  }, [url]);

  useEffect(() => {
    // reset the history when name changed
    historyOpts.current.initialEntries = [url];
    historyOpts.current.initialIndex = 1;
  }, [componentProps.name]);

  return (
    <MicroApp
      {...defaultProps}
      {...rest}
      history={historyOpts.current}
      onHistoryInit={historyInitHandler}
    />
  );
}
